/* === LICENSE INFO ===
 * This source file is subject to the GPLv3 license that is bundled with this
 * package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl.txt
 * === end of LICENSE INFO === */

/*==============================================================================
  File Name   : LogWriterManager.hpp
  Description : Declaration for LogWriterManager class in GLog module.

  Created on  : 2009-10-01
  Updated on  : 2011-01-03
  Updated by  : Lee Shiou Ming

  Cautions    : (important notes)
  ============================================================================*/

#ifndef LOGWRITERMANAGER_HPP_
#define LOGWRITERMANAGER_HPP_

#include "GLogDefinition.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include <string>
#include <vector>

#define DEFAULT_ASYNC_LOGGING_IDLE 2


/**
 * @brief All gUtil modules will be wrapped within gUtil namespace.
 */
namespace gUtil
{
/**
 * @brief Namespace for GLog module.
 */
namespace GLog
{
    class LogWriter;

    /**
     * @brief Class that manages all log writers.
     *
     * It is designed that caller shouldn't interact with log writers directly.
     * Instead, logging request will be forwarded by this class to corresponding
     * log writers which are being managed.
     */
    class LogWriterManager
    {
    public:
        //=== public TYPES ===
        /**
         * @brief Wrapped log writer pointer within smart pointer. Please use
         *        this smart pointer instead of native pointer.
         */
        typedef boost::shared_ptr<LogWriter> LogWriterPtr;
        //=== end of public TYPES ===

        /**
         * @brief Constructor performs member initialization.
         */
        LogWriterManager();

        /**
         * @brief Destructor joins the the dedicated logging thread if it has
         *        been started.
         */
        ~LogWriterManager();

        /**
         * @brief Interface for setting path of log file.
         *
         * @param _logFilePath
         * [IN] Path of log file.
         *
         * @return
         * - true ==> Succeed.
         * - false ==> Failed.
         */
        bool setLogFilePath(const std::string& _logFilePath);

        /**
         * @brief Interface for setting log file rotation size.
         *
         * @param _logRotationSize
         * [IN] Log file rotation size, in byte.
         *
         * @return
         * - true ==> Succeed.
         * - false ==> Failed.
         */
        bool setLogRotationSize(unsigned int _logRotationSize);

        /**
         * @brief Interface for setting log file rotation interval.
         *
         * @param _logRotationInterval
         * [IN] New log file rotation interval.
         *
         * @return
         * - true ==> Succeed.
         * - false ==> Failed.
         */
        bool setLogRotationInterval(TimeInterval _logRotationInterval);

        /**
         * @brief Create a log writer of given output type and put it under
         *        management.
         *
         * Logger initialization should call this function for each of the
         * enabled log output type.
         *
         * @param _enabledOutput
         * [IN] Log writer of this output type will be created.
         *
         * @return
         * - true ==> Succeed.
         * - false ==> Failed.
         */
        bool createLogWriter(const LogOutputType _enabledOutput);

        /**
         * @brief Start the dedicated logging thread.
         *
         * It is caller's responsibility to ensure the thread safety of
         * invocation (in this case, class GLog is the caller).
         *
         * @param _idleDuration
         * [IN] Amount of time in second for logging thread to idle whenever
         *      there is no logging task. Default value (2 seconds) will be use
         *      if pass in a value of no greater than 0.
         *
         * @return
         * - true ==> Succeed.
         * - false ==> Asynchronous logging was already started, or encounter
         *             error when trying to start it.
         */
        bool startAsyncLogging(
                const unsigned int _idleDuration = DEFAULT_ASYNC_LOGGING_IDLE);

        /**
         * @brief Forward logging request (append) to log writers, either
         *        synchronously or asynchronously.
         *
         * @param _logMessage
         * [IN] Log message that will be forwarded to log writer.
         * @param _logLevelString
         * [IN] Log level string that will be forwarded to log writer.
         */
        void appendLog(const std::string& _logMessage,
                const std::string& _logLevelString);

    private:
        /**
         * @brief Path of log file.
         */
        std::string m_logFilePath;

        /**
         * @brief Maximum size of each log file in byte.
         *
         * Will be effective only if the value is greater than zero.
         */
        unsigned int m_logRotationSize;

        /**
         * @brief Time interval of log file rotation.
         */
        TimeInterval m_logRotationInterval;

        /**
         * @brief Holding pointers for all log writer objects that are being
         *        managed.
         */
        std::vector<LogWriterPtr> m_logWriters;

        /**
         * @brief Dedicated logging thread, allows client to do asynchronous
         *        logging.
         *
         * To client, they are logging asynchronously by using this utility.
         * Internally within this utility's dedicated thread, log messages are
         * written synchronously, to avoid multithreading's concurrency issue.
         */
        boost::thread m_loggingThread;

        /**
         * @brief Interface to OS I/O service, needed to support asynchronous
         *        I/O.
         */
        boost::asio::io_service m_ioService;

        /**
         * @brief For I/O service to support synchronous execution of
         *        asynchronous operations' completion handlers.
         */
        boost::asio::strand m_strand;

        /**
         * @brief This flag indicates if the dedicated logging thread is
         *        started.
         */
        volatile bool m_isAsyncLoggingStarted;

        /**
         * @brief With this flag set to true, the dedicated logging thread will
         *        exit from its thread function's internal loop.
         */
        volatile bool m_isLoggingStopRequested;

        /**
         * @brief The dedicated logging thread will sleep and idle for x seconds
         *        if there is no logging job.
         */
        unsigned int m_asyncIdleDuration;

        /**
         * @brief The dedicated logging thread will be running and looping
         *        within this thread function.
         */
        void* loggingThreadFunc();

    };  /* end of class LogWriterManager */

}  /* end of namespace GLog */
}  /* end of namespace gUtil */

#endif  /* LOGWRITERMANAGER_HPP_ */
